package com.bfsuol.bfsuolframework.core.dao.keygen;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;

import javax.sql.DataSource;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;

public class OracleDBKeyGen implements KeyGen, InitializingBean {

    private static int POOL_SIZE = 1;       //Sequence值缓存大小
    private Map<String, KeyInfo> keyMap = new HashMap<String, KeyInfo>(20); //Sequence载体容器

    private DataSource dataSource;//数据库连接
	public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}
	public DataSource getDataSource() {return this.dataSource;}

	public void afterPropertiesSet() {
		if (this.dataSource == null) {
			throw new IllegalArgumentException("必须输入数据源");
		}
	}
	
    public OracleDBKeyGen() {
    }


    /**
     * 获取下一个Sequence键值
     * @param keyName Sequence名称
     * @return 下一个Sequence键值
     */
    public long getNextValue(String key,int start,int maxValue,int incrementer) {
        KeyInfo keyInfo = null;
        Long keyObject = null;
        try {
            if (keyMap.containsKey(key)) {
                keyInfo = keyMap.get(key);
            } else {
                keyInfo = new KeyInfo(key, start, maxValue, incrementer);
                keyMap.put(key, keyInfo);
            }
            keyObject = keyInfo.getNextKey();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return keyObject;
    }
    
    
    public class KeyInfo {

		private long start;        //当前Sequence载体的最大值
        private long max;        //当前Sequence载体的最小值
        private long incrementer;       //下一个Sequence值
        
        private String key;     //Sequence的名称
        
        private long maxValue = 0;
        private long nextValue = 0;
        private static final String SQL_UPDATE = "UPDATE KEYTABLE SET KEYVALUE = KEYVALUE + ? WHERE KEYNAME = ?";
        private static final String SQL_QUERY = "SELECT KEYVALUE FROM KEYTABLE WHERE KEYNAME = ?";

        public KeyInfo(String key, long start, long max, long incrementer) {
			this.start = start;
			this.max = max;
			this.incrementer = incrementer;
			this.key = key;
            //TODO 读取数据库
			
        }
		public long getStart() {
			return start;
		}
		public long getMax(){
        	return max;
        }
		public long getIncrementer() {
			return incrementer;
		}
		public String getKey() {
			return key;
		}
        
		public long getMaxValue() {
			return maxValue;
		}

        /**
         * 获取下一个Sequence值
         *
         * @return 下一个Sequence值
         * @throws SQLException
         */
        public synchronized long getNextKey() throws SQLException {
            if (nextValue > maxValue) {
            	maxValue = getNaxtMaxValue();
            }
            return nextValue++;
        }

        /**
         * 执行Sequence表信息初始化和更新工作
         *
         * @throws SQLException
         */
        
        private long getNaxtMaxValue() throws DataAccessResourceFailureException{
        	Connection con = DataSourceUtils.getConnection(getDataSource());
        	PreparedStatement stmt = null;
        	PreparedStatement stmt_up = null;
    		ResultSet rs = null;
    		try {
    			stmt = con.prepareStatement(SQL_QUERY);
    			stmt.setString(1, key);
    			DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
    			rs = stmt.executeQuery();
    			if (rs.next()) {
    				rs.close();
                    stmt.close();
                    
                    //更新数据库
                    con.setAutoCommit(false);
                    stmt_up = con.prepareStatement(SQL_UPDATE);
                    stmt_up.setLong(1, POOL_SIZE);
                    stmt_up.setString(2, key);
                    stmt_up.executeUpdate();
                    stmt_up.close();
                    con.commit();
                    //设置值
                    return rs.getLong(1);
    			}else {
    				return insertKey();
    			}
    		}
    		catch (SQLException e) {
    			createTable();
    			return insertKey();
    		}
    		finally {
    			JdbcUtils.closeResultSet(rs);
    			JdbcUtils.closeStatement(stmt);
    			DataSourceUtils.releaseConnection(con, getDataSource());
    		}
        }
        
        /**
    	 * 创建新的sequence
    	 * @param key
    	 * @param start
    	 * @param maxValue
    	 * @param incrementer
    	 */
    	private void createTable() {
    		Connection con = DataSourceUtils.getConnection(getDataSource());
    		Statement stmt = null;
    		String sql = "CREATE TABLE keytable (KEYNAME varchar(100) NOT NULL , KEYVALUE number(19) DEFAULT '0')";
    		try {
    			stmt = con.createStatement();
    			DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
    			stmt.executeUpdate(sql);
    		}
    		catch (SQLException ex) {
    			throw new DataAccessResourceFailureException("create sequence fail !", ex);
    		}
    		finally {
    			JdbcUtils.closeStatement(stmt);
    			DataSourceUtils.releaseConnection(con, getDataSource());
    		}
    	}
    	
    	/**
    	 * 创建新的sequence
    	 * @param key
    	 * @param start
    	 * @param maxValue
    	 * @param incrementer
    	 */
    	private long insertKey() throws DataAccessResourceFailureException{
    		Connection con = DataSourceUtils.getConnection(getDataSource());
    		Statement stmt = null;
    		StringBuffer sql = new StringBuffer();
    		sql.append("INSERT INTO KEYTABLE(KEYNAME,KEYVALUE) VALUES('").append(key).append("',").append(start+POOL_SIZE).append(")");
    		try {
    			stmt = con.createStatement();
    			DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
    			stmt.executeUpdate(sql.toString());
    		}
    		catch (SQLException ex) {
    			throw new DataAccessResourceFailureException("create sequence fail !", ex);
    		}
    		finally {
    			JdbcUtils.closeStatement(stmt);
    			DataSourceUtils.releaseConnection(con, getDataSource());
    		}
    		return start+POOL_SIZE;
    	}
    }

}
